﻿using System;
using System.Collections;
using UnityEngine;

namespace ZFramework.Runtime
{
    public class GameWorldManager : FrameworkManagerBase, IGameWorldManager
    {
        private FsmManager m_FsmManager;
        private Fsm<IGameWorldManager> m_GameWorldFsm;

        [SerializeField]
        private string[] m_AvailableGameWorldTypeNames = null;

        [SerializeField]
        private string m_EntranceGameWorldTypeName = null;
        
        private GameWorldBase m_EntranceGameWorld = null;
        
        /// <summary>
        /// 获取当前流程。
        /// </summary>
        public GameWorldBase CurrentGameWorld
        {
            get
            {
                if (m_GameWorldFsm == null)
                {
                    throw new FrameworkException("You must initialize gameWorld first.");
                }

                return (GameWorldBase)m_GameWorldFsm.CurrentState;
            }
        }

        /// <summary>
        /// 获取当前流程持续时间。
        /// </summary>
        public float CurrentGameWorldTime
        {
            get
            {
                if (m_GameWorldFsm == null)
                {
                    throw new FrameworkException("You must initialize gameWorld first.");
                }

                return m_GameWorldFsm.CurrentStateTime;
            }
        }

        protected override void Awake()
        {
            base.Awake();
            m_FsmManager = null;
            m_GameWorldFsm = null;
        }

        private IEnumerator Start()
        {
            m_FsmManager = FrameworkManagerManager.GetManager<FsmManager>();
            if (m_FsmManager == null)
            {
                Log.Error("FsmManager is invalid.");
                yield break;
            }
            GameWorldBase[] gameWorlds = new GameWorldBase[m_AvailableGameWorldTypeNames.Length];
            for (int i = 0; i < m_AvailableGameWorldTypeNames.Length; i++)
            {
                Type gameWorldType = Utility.Assembly.GetType(m_AvailableGameWorldTypeNames[i]);
                if (gameWorldType == null)
                {
                    Log.Error("Can not find gameWorld type '{0}'.", m_AvailableGameWorldTypeNames[i]);
                    yield break;
                }

                gameWorlds[i] = (GameWorldBase)Activator.CreateInstance(gameWorldType);
                if (gameWorlds[i] == null)
                {
                    Log.Error("Can not create gameWorld instance '{0}'.", m_AvailableGameWorldTypeNames[i]);
                    yield break;
                }

                if (m_EntranceGameWorldTypeName == m_AvailableGameWorldTypeNames[i])
                {
                    m_EntranceGameWorld = gameWorlds[i];
                }
            }
            
            if (m_EntranceGameWorld == null)
            {
                Log.Error("Entrance gameWorld is invalid.");
                yield break;
            }

            m_GameWorldFsm = m_FsmManager.CreateFsm(this, "GameWorld", gameWorlds);
            
            yield return new WaitForEndOfFrame();
            
            m_GameWorldFsm.Start(m_EntranceGameWorld.GetType());
        }
        
        public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
        {
            
        }

        public override void Shutdown()
        {
            if (m_FsmManager != null)
            {
                if (m_GameWorldFsm != null)
                {
                    m_FsmManager.DestroyFsm(m_GameWorldFsm);
                    m_GameWorldFsm = null;
                }

                m_FsmManager = null;
            }
        }

        public void StartGameWorld<T>() where T : GameWorldBase
        {
            if (m_GameWorldFsm == null)
            {
                throw new FrameworkException("You must initialize gameWorld first.");
            }

            m_GameWorldFsm.Start<T>();
        }

        public void StartGameWorld(Type gameWorldType)
        {
            if (m_GameWorldFsm == null)
            {
                throw new FrameworkException("You must initialize gameWorld first.");
            }

            m_GameWorldFsm.Start(gameWorldType);
        }

        public bool HasGameWorld<T>() where T : GameWorldBase
        {
            if (m_GameWorldFsm == null)
            {
                throw new FrameworkException("You must initialize gameWorld first.");
            }

            return m_GameWorldFsm.HasState<T>();
        }

        public bool HasGameWorld(Type gameWorldType)
        {
            if (m_GameWorldFsm == null)
            {
                throw new FrameworkException("You must initialize gameWorld first.");
            }

            return m_GameWorldFsm.HasState(gameWorldType);
        }

        public GameWorldBase GetGameWorld<T>() where T : GameWorldBase
        {
            if (m_GameWorldFsm == null)
            {
                throw new FrameworkException("You must initialize gameWorld first.");
            }

            return m_GameWorldFsm.GetState<T>();
        }

        public GameWorldBase GetGameWorld(Type gameWorldType)
        {
            if (m_GameWorldFsm == null)
            {
                throw new FrameworkException("You must initialize gameWorld first.");
            }

            return (GameWorldBase)m_GameWorldFsm.GetState(gameWorldType);
        }
    }
}